<template>
  <div class="tree" @mouseout="handleMouseOut" @mouseover="handleMouseOver">
    <vab-card
      class="auto-height-card has-header"
      :style="{
        border: !foldedState || !isCardBorder ? 'none' : '1px solid var(--el-border-color)',
        '--cardBody': isEdit && isHeader ? '340px' : '250px',
      }"
    >
      <template v-if="isEdit && isHeader" #header>
        <div class="card-header">
          <span v-show="foldedState">{{ name }}</span>
          <el-button v-if="optAuthority.includes(7)" v-show="foldedState" :icon="Plus" link type="primary" @click="addTree">新增</el-button>
        </div>
      </template>
      <div class="tree_conten_box" style="height: 100%">
        <el-input
          v-if="isSearch"
          v-show="foldedState"
          v-model="search"
          clearable
          placeholder="搜索层级名称"
          style="width: 100%"
          @input="searchChang"
        />
        <slot name="add"></slot>

        <el-tree
          v-show="foldedState"
          v-bind="attrs"
          ref="TreeRef"
          :data="treeList"
          :default-expanded-keys="expandedKeysData"
          :highlight-current="true"
          node-key="id"
          @check="handleCheckChange"
          @current-change="treeChange"
          @node-click="nodeClick"
        >
          <template #default="{ node, data }">
            <div class="tree_content" @contextmenu="onContextMenu($event, data)">
              <p v-if="data.isFinish" class="dot"></p>
              <span>
                {{ node.label }}
                <template v-if="isTotal">
                  (
                  <span class="cred">{{ data.total || data.count }}</span>
                  )
                </template>
              </span>
              <el-dropdown v-if="isEdit" class="icon">
                <el-icon><more-filled /></el-icon>
                <template #dropdown>
                  <el-dropdown-menu>
                    <el-dropdown-item v-if="optAuthority.includes(1) && node.label != '全部'" @click="append(data[parentId], data)">
                      <el-icon class="samelevel"><plus /></el-icon>
                      添加同级
                    </el-dropdown-item>
                    <el-dropdown-item v-if="optAuthority.includes(2)" @click="append(data.id, data)">
                      <el-icon class="subordinate"><plus /></el-icon>
                      添加下级
                    </el-dropdown-item>
                    <el-dropdown-item v-if="optAuthority.includes(3)" @click="editData(data)">
                      <el-icon><edit /></el-icon>
                      编辑
                    </el-dropdown-item>
                    <el-dropdown-item v-if="optAuthority.includes(4)" @click="remove(data)">
                      <el-icon><delete /></el-icon>
                      删除
                    </el-dropdown-item>
                    <el-dropdown-item v-if="optAuthority.includes(5)" :disabled="data.isMoveUp" @click="upOrDownFn(data, true)">
                      <el-icon><upload /></el-icon>
                      上移
                    </el-dropdown-item>
                    <el-dropdown-item v-if="optAuthority.includes(6)" :disabled="data.isMoveDown" @click="upOrDownFn(data, false)">
                      <el-icon><download /></el-icon>
                      下移
                    </el-dropdown-item>
                  </el-dropdown-menu>
                </template>
              </el-dropdown>
            </div>
          </template>
        </el-tree>
        <template v-if="isEdit">
          <vab-context-menu v-model:show="show" :options="options">
            <vab-context-menu-item
              v-if="optAuthority.includes(1) && options.data.name != '全部'"
              class="context-menu-item"
              @click="append(options.data[parentId], options.data)"
            >
              <div class="contextMenu">
                <el-icon class="samelevel"><plus /></el-icon>
                添加同级
              </div>
            </vab-context-menu-item>
            <vab-context-menu-item v-if="optAuthority.includes(2)" class="context-menu-item" @click="append(options.data.id, options.data)">
              <div class="contextMenu">
                <el-icon class="subordinate"><plus /></el-icon>
                添加下级
              </div>
            </vab-context-menu-item>
            <vab-context-menu-item v-if="optAuthority.includes(3)" class="context-menu-item" @click="editData(options.data)">
              <div class="contextMenu">
                <el-icon><Edit /></el-icon>
                编辑
              </div>
            </vab-context-menu-item>
            <vab-context-menu-item v-if="optAuthority.includes(4)" class="context-menu-item" @click="remove(options.data)">
              <div class="contextMenu">
                <el-icon><delete /></el-icon>
                删除
              </div>
            </vab-context-menu-item>
            <vab-context-menu-item
              v-if="optAuthority.includes(5)"
              class="context-menu-item"
              :disabled="options.data.isMoveUp"
              @click="upOrDownFn(options.data, true)"
            >
              <div class="contextMenu">
                <el-icon><upload /></el-icon>
                上移
              </div>
            </vab-context-menu-item>
            <vab-context-menu-item
              v-if="optAuthority.includes(6)"
              class="context-menu-item"
              :disabled="options.data.isMoveDown"
              @click="upOrDownFn(options.data, false)"
            >
              <div class="contextMenu">
                <el-icon><download /></el-icon>
                下移
              </div>
            </vab-context-menu-item>
          </vab-context-menu>
        </template>
      </div>
    </vab-card>
    <div v-if="isFolded" v-show="foldedStateClass" :class="foldedState ? 'foldedStateClass' : 'foldedStateClass r5'" @click="folded">
      {{ foldedState ? '收起' : '展开' }}
      <el-icon>
        <arrow-left-bold v-if="foldedState" />
        <arrow-right-bold v-else />
      </el-icon>
    </div>
  </div>
</template>

<script lang="ts" setup>
import { ArrowLeftBold, ArrowRightBold, Delete, Download, Edit, MoreFilled, Plus, Upload } from '@element-plus/icons-vue'
import { defineProps, useAttrs } from 'vue'
import { upOrDown } from '/@/api/category'
import { VabContextMenu, VabContextMenuItem } from '/@/plugins/VabContextMenu'

const emit = defineEmits([
  'update',
  'update:modelValue',
  'append',
  'edit',
  'addTree',
  'remove',
  'folded',
  'search',
  'nodeClick',
  'current-change',
  'check',
])
const attrs: any = useAttrs()

const props = defineProps({
  // 基础属性
  name: {
    type: String,
    default: '',
  },

  // 数据相关
  modelValue: {
    type: Array,
    default: () => [],
  },
  // 总数字段
  totalField: {
    type: String,
    default: '',
  },
  // 是否需要显示分类总数
  isTotal: {
    type: Boolean,
    default: false,
  },

  // 控制属性
  // 是否需要搜索
  isSearch: {
    type: Boolean,
    default: true,
  },
  // 是否需要展开收起
  isFolded: {
    type: Boolean,
    default: true,
  },
  // 是否编辑状态
  isEdit: {
    type: Boolean,
    default: true,
  },
  // 是否需要加一层全部
  isWhole: {
    type: Boolean,
    default: true,
  },
  // 是否需要边框
  isCardBorder: {
    type: Boolean,
    default: true,
  },
  // 是否需要标题
  isHeader: {
    type: Boolean,
    default: true,
  },

  // 目录结构相关
  // 父级id字段
  parentId: {
    type: String,
    default: 'pid',
  },

  // 增删改查分类组件
  componentName: {
    type: Object,
    default: () => {},
  },
  // 组件参数
  componentProps: {
    type: Object,
    default: () => ({}),
  },

  // 操作权限
  optAuthority: {
    type: Array,
    default: () => [1, 2, 3, 4, 5, 6, 7],
  },

  // 样式相关
  // 弹框宽度
  dialogWidth: {
    type: String,
    default: '500px',
  },
  // 默认展开
  expandedKeys: {
    type: Array,
    default: () => [''],
  },
})
const upDataPid = ref<any>([])
const expandedKeysData: any = computed(() => [...props.expandedKeys, ...upDataPid.value])
const search = ref<any>()
const foldedStateClass = ref<boolean>(false)
const foldedState = ref<boolean>(true)
const show = ref<any>(false) //鼠标右键
const options = reactive<any>({ minWidth: 100, x: 500, y: 200, data: undefined })
const TreeRef = ref<any>()
const handleMouseOver = () => {
  if (foldedState.value) {
    foldedStateClass.value = true
  }
}
const handleMouseOut = () => {
  if (foldedState.value) {
    foldedStateClass.value = false
  } else {
    foldedStateClass.value = true
  }
}
const setLabel = (data: any[]) => {
  // 资产分类树 初始化

  data.forEach((item: any, index: number) => {
    item.isMoveUp = index === 0 //是否可以向上移动
    item.isMoveDown = index === data.length - 1 //是否可以向下移动
    if (item[attrs.props.children] && item[attrs.props.children].length > 0) {
      item.isFinish = false
      setLabel(item[attrs.props.children])
    } else {
      item.isFinish = true //圆点
    }
  })
  let total = 0
  data.forEach((item: any) => {
    total += item[props.totalField]
  })
  let tree: any[] = []

  if (data.length > 0) {
    tree = [
      {
        [attrs.props.label]: '全部',
        code: '',
        children: data,
        id: '',
        isMoveUp: true,
        isMoveDown: true,
        isFinish: false,
        total,
      },
    ]
  }

  if (props.isWhole) {
    return tree
  }
  return data
}
const treeList = computed({
  get: () => setLabel(props.modelValue),
  set: (val) => emit('update:modelValue', val),
})

const append = (id: any, data: any): void => {
  //新增资产分类树
  emit('append', id, data)
}
const addTree = (): void => {
  emit('addTree')
}
const editData = (data: any): void => {
  //编辑资产分类树
  emit('edit', data)
}
const remove = (data: any): void => {
  //删除资产分类树
  emit('remove', data)
}

//上移下移时 获取所有同级数据
const findParent = (data: any[], id: string): any | null => {
  let result: any | null = null
  let ids = id === '0' ? '' : id
  const findParentRecursive = (items: any[]) => {
    for (const item of items) {
      if (item.id == ids) {
        result = item.children
        break
      }
      if (item.children && item.children.length > 0) {
        findParentRecursive(item.children)
        if (result) break
      }
    }
  }
  findParentRecursive(data)
  result = result === null ? data : result
  return result.map((item: any) => item.id)
}
// 获取移动完之后的id集合
const moveValueInArray = (arr: any[], target: string, moveForward: boolean): string[] => {
  const newArr = [...arr]
  const targetIndex = newArr.indexOf(target)
  if (targetIndex !== -1) {
    const newIndex = moveForward ? targetIndex - 1 : targetIndex + 1
    if (newIndex >= 0 && newIndex < newArr.length) {
      newArr.splice(targetIndex, 1)
      newArr.splice(newIndex, 0, target)
    }
  }
  return newArr
}

const treeChange = (data: any): void => {
  emit('current-change', data)
}

const nodeClick = (node: any): void => {
  // 分类树点击
  expandedKeysData.value = Array.from(new Set([node.id, ...expandedKeysData.value]))
  emit('nodeClick', node)
}
// 选中复选框
const handleCheckChange = (data: any, node: any) => {
  emit('check', data, node)
}
// true上移 false下移
const upOrDownFn = (data: any, state: boolean) => {
  let id = data[props.parentId] ? data[props.parentId] : ''
  let ids = findParent(treeList.value, id)
  let array = moveValueInArray(ids, data.id, state)
  upOrDown(array).then(() => {
    emit('update')
  })
}
// 鼠标右键
const onContextMenu = (e: any, data: any) => {
  e.preventDefault()
  options.x = e.x
  options.y = e.y
  show.value = true
  options.data = data
}

// 折叠收起 true折叠 false收起
const folded = () => {
  emit('folded', foldedState.value)
  foldedState.value = !foldedState.value
}
// 搜索
const searchChang = () => {
  emit('search', search.value)
}
</script>

<style lang="scss" scoped>
.tree {
  position: relative;
  height: 100%;
  .cred {
    color: #f89898;
  }
  .card-header {
    display: flex;
    gap: 10px;
    justify-content: space-between;
    width: 100%;
    height: 20px;
  }
  .foldedStateClass {
    position: absolute;
    top: 40%;
    right: 0px;
    display: flex;
    flex-direction: column;
    width: 22px;
    height: 55px;
    padding: 5px;
    font-size: 12px;
    line-height: 15px;
    color: var(--el-color-primary);
    text-align: center;
    cursor: pointer;
    background-color: var(--el-color-primary-light-9);
    border-radius: 3px;
  }
  .r5 {
    right: -4px;
  }
  .tree_conten_box {
    display: flex;
    flex-direction: column;
    gap: 10px;
  }
  .tree_content {
    position: relative;
    width: 100%;
    .icon {
      position: absolute;
      top: 0px;
      right: 5px;
      display: none;
    }
  }
  .dot {
    position: absolute;
    top: 6px;
    left: -18px;
    width: 8px;
    height: 8px;
    background-color: #b8b8b8;
    border-radius: 50%;
  }
  .contextMenu {
    display: flex;
    gap: 5px;
    align-items: center;
  }

  ::v-deep {
    .el-tree-node {
      --el-tree-node-hover-bg-color: rgba(24, 144, 255, 0.1) !important; /* 将变量值修改为您需要的颜色值 */
    }
    .el-tree-node__content {
      &:hover .icon {
        display: block;
      }
    }
    .tree_content {
      position: relative;
    }

    .el-card__body {
      height: calc(100vh - var(--cardBody));
      padding: 12px !important;
      overflow-y: scroll;
    }
    .el-card {
      height: calc(100% - 20px) !important;
    }
  }
}
.samelevel {
  border: 1px solid #000;
}
.subordinate {
  border: 1px dashed #000;
}
::v-deep {
  .mx-context-menu-item {
    cursor: pointer !important;
  }
}
</style>
